#include "autobuy.h"

#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QToolButton>
#include <QStyle>

/**
 * AutoBuyUpgradeLabel
 */
AutoBuyUpgradeLabel::AutoBuyUpgradeLabel( const UpgradeType nType, QWidget * parent )
    : QWidget( parent )
    , type( nType ) {
    QHBoxLayout * layout = new QHBoxLayout{ this };

    QLabel * icon = new QLabel{};
    icon->setPixmap( QPixmap{ ":/upgrade/" + QString::fromStdString( Upgrade::getNameByType( type ) ) }.scaledToWidth( 18, Qt::SmoothTransformation ) );
    count = new QLabel{};

    layout->addWidget( icon );
    layout->addWidget( count );
}

UpgradeType AutoBuyUpgradeLabel::getType() const {
    return type;
}

void AutoBuyUpgradeLabel::setNumber( int64_t nCount ) {
    count->setText( QString::number( nCount ) );
}

void AutoBuyUpgradeLabel::reset() {
    count->setText( QString() );
}

/**
 * AutoBuyUpgradeInfo
 */
AutoBuyUpgradeInfo::AutoBuyUpgradeInfo( std::initializer_list<UpgradeType> typeList, QWidget * parent )
    : QWidget( parent ) {
    QGridLayout * layout = new QGridLayout{ this };
    layout->setMargin( 0 );
    layout->setSpacing( 0 );
    // info labels
    int row = 0;
    int column = 0;
    for ( UpgradeType type : typeList )
    {
        labels.push_back( new AutoBuyUpgradeLabel{ type, this } );
        layout->addWidget( labels.back(), row, column );
        column++;
        if ( column > 2 )
        {
            row++;
            column = 0;
        }
    }
    // close button
    QToolButton * closeButton = new QToolButton{ this };
    closeButton->setIcon( style()->standardIcon( QStyle::SP_DialogOkButton ) );
    closeButton->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
    layout->addWidget( closeButton, row, column, 1, -1 );
    connect( closeButton, &QToolButton::released, this, &AutoBuyUpgradeInfo::closed );
    connect( closeButton, &QToolButton::released, this, &AutoBuyUpgradeInfo::reset );
}

void AutoBuyUpgradeInfo::setNumber( UpgradeType nType, int64_t nCount ) {
    for ( AutoBuyUpgradeLabel * l : labels )
    {
        if ( l->getType() == nType )
        { l->setNumber( nCount ); }
    }
}

void AutoBuyUpgradeInfo::reset() {
    for ( AutoBuyUpgradeLabel * l : labels )
    { l->reset(); }
}

/**
 * AutoBuyInfo
 */
AutoBuyInfo::AutoBuyInfo( QWidget * parent )
    : QWidget( parent ) {
    // "Spend all" buttons for xp and asset
    QToolButton * spendAsset = new QToolButton{ this };
    spendAsset->setIcon( QIcon{ ":/product/Asset" } );
    connect( spendAsset, &QToolButton::released, this, [this]() { emit buyAll( ProductType::Asset ); } );
    QToolButton * spendXP = new QToolButton{ this };
    spendXP->setIcon( QIcon{ ":/product/XP" } );
    connect( spendXP, &QToolButton::released, this, [this]() { emit buyAll( ProductType::XP ); } );

    // step buttons
    QVBoxLayout * layout = new QVBoxLayout{ this };
    QHBoxLayout * stepLayout = new QHBoxLayout{};
    layout->addLayout( stepLayout );

    for ( int step = 0; step < 3; ++step )
    {
        QToolButton * stepButton = new QToolButton{ this };
        stepButton->setCheckable( true );
        stepButton->setSizePolicy( QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Fixed );
        stepButton->setObjectName( QString::number( pow10( step ) ) );
        stepButton->setToolTip( "Buy " + stepButton->objectName() + " upgrades in one time" );
        stepButton->setText( QString( "%1x" ).arg( pow10( step ) ) );
        stepLayout->addWidget( stepButton );
        connect( stepButton, &QToolButton::toggled, this, [this, step]( bool toggle ) {
            if ( toggle )
            { emit stepChanged( static_cast<int>( pow10( step ) ) ); }
        } );
    }

    QGridLayout * buyLayout = new QGridLayout{};
    layout->addLayout( buyLayout );
    buyLayout->addWidget( new QLabel( "SPEND ALL" ), 0, 0, Qt::AlignVCenter | Qt::AlignRight );
    buyLayout->addWidget( spendAsset, 0, 1 );
    buyLayout->addWidget( spendXP, 0, 2 );
}

/**
 * AutoBuyWidget
 */
AutoBuyWidget::AutoBuyWidget( std::shared_ptr<State> state, QWidget * parent )
    : QStackedWidget( parent )
    , playerData( state ) {
    labInfo = new AutoBuyUpgradeInfo{ { UpgradeType::Generator_Power, UpgradeType::Generator_XP, UpgradeType::Generator_Asset, UpgradeType::Effeciency_SolarPanel,
                                        UpgradeType::Effeciency_WindWill, UpgradeType::Effeciency_Reflector, UpgradeType::Cost_Reduction_Assets,
                                        UpgradeType::Cost_Reduction_Orb },
                                      this };

    buildInfo = new AutoBuyUpgradeInfo{ { UpgradeType::SolarPanel, UpgradeType::WindMill, UpgradeType::Reflector }, this };

    buyInfo = new AutoBuyInfo{ this };
    connect( buyInfo, &AutoBuyInfo::buyAll, this, &AutoBuyWidget::buyAll );
    connect( buyInfo, &AutoBuyInfo::stepChanged, this, &AutoBuyWidget::stepChanged );

    addWidget( buyInfo );
    addWidget( buildInfo );
    addWidget( labInfo );
    connect( labInfo, &AutoBuyUpgradeInfo::closed, this, [this]() { setCurrentIndex( 0 ); } );
    connect( buildInfo, &AutoBuyUpgradeInfo::closed, this, [this]() { setCurrentIndex( 0 ); } );
}

void AutoBuyWidget::buyAll( ProductType nType ) {
    std::map<UpgradeType, int64_t> upgradeList = playerData->upgradeAll( nType );
    for ( auto [t, l] : upgradeList )
    {
        if ( nType == ProductType::Asset )
        {
            buildInfo->setNumber( t, l );
        } else if ( nType == ProductType::XP )
        {
            labInfo->setNumber( t, l );
        } else
        {
            /* TODO buy all possible orbs? */
            assert( false );
        }
    }
    if ( nType == ProductType::Asset )
    {
        setCurrentIndex( 1 );
    } else if ( nType == ProductType::XP )
    { setCurrentIndex( 2 ); }
    // emit false "step change" for data update
    emit stepChanged( playerData->getStep( UpgradeType::SolarPanel ) );
}

void AutoBuyWidget::updateData( const State & state ) {
    const QString step = QString( "%1" ).arg( state.getStep( UpgradeType::SolarPanel ) );
    for ( QToolButton * s : buyInfo->findChildren<QToolButton *>( QString{}, Qt::FindDirectChildrenOnly ) )
    {
        if ( !s->objectName().isEmpty() )
        {
            s->setEnabled( s->objectName() != step );
            s->setChecked( s->objectName() == step );
        }
    }
}
